#include <SDL/SDL_image.h>
#include <algorithm>
#include "Utils\\Font.h"
#include "Utils\\Color.h"
#include "BlocManager.h"

using namespace SDL::UTILS;

static void FiltreIncrustation(SDL_Surface* _s, Color _f)
{
	for (int y = 0; y < _s->h; y++)
	{
		for (int x = 0; x < _s->w; x++)
		{
			Uint32 px = Surface::GetPixel(_s, x, y);
			Color c(px);
			Surface::SetPixel(_s, c.ToUint32(), x, y);
		}
	}
}

#include <windows.h>
#include <iostream>

// http://msdn.microsoft.com/en-us/library/aa365200(v=vs.85).aspx

static void LoadBlocs(Sprites& _sprites,
					  std::map<std::string, Bloc*>& _originalBlocs)
{
	std::string base = "sprites\\blocs\\";
	WIN32_FIND_DATA wfd;
	wchar_t dir[] = L"sprites\\blocs\\*";
	HANDLE hFind = FindFirstFile(dir, &wfd);
	if (hFind == INVALID_HANDLE_VALUE)
	{
		std::cerr << "sprites\\blocs nof found" <<std::endl;
		return ;
	}

	do
	{
		if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			continue ;
		std::wstring filename = wfd.cFileName;
		if (filename.size() < 5)
			continue ;
		std::wstring ext = filename.substr(filename.size() - 3);
		if (ext != L"png")
			continue ;
		std::wstring name = filename.substr(0, filename.size() - 4);
			
		std::string sName = Font::WStringToString(name);
		std::string sFileName = Font::WStringToString(filename);

		Sprite s(sName, IMG_Load(std::string(base + sFileName).c_str()),
				 Rect(0, 0, 32, 16));
		_sprites.GetSprites().push_back(s);
		_originalBlocs[sName] = new Bloc(sName, s);

	} while (FindNextFile(hFind, &wfd) != 0);
	FindClose(hFind);
}

static void LoadSprites(Sprites& _sprites,
						std::map<std::string, Bloc*>& _originalBlocs)
{
	LoadBlocs(_sprites, _originalBlocs);
}

BlocManager::BlocManager()
{
	//m_sprites.GetSprites().push_back(Sprite("normal", IMG_Load("normalBloc.png"), Rect(0, 0, 32, 16)));
	m_sprites.GetSprites().push_back(Sprite("death", IMG_Load("deathBloc.png"), Rect(0, 0, 64, 64), 100));
	//m_sprites.GetSprites().push_back(Sprite("static", IMG_Load("staticBloc.png"), Rect(0, 0, 32, 16)));
	LoadSprites(m_sprites, m_originalBlocs);

	//m_originalBlocs["normal"] = new Bloc("normal", *m_sprites.Find("normal"));
	//m_originalBlocs["static"] = new Bloc("static", *m_sprites.Find("static"));

	/*SDL_Surface* s = IMG_Load("staticBloc.png");
	FiltreIncrustation(s, Color(100, 0, 0));
	m_sprites.GetSprites().push_back(Sprite("red", s, Rect(0, 0, 32, 16)));
	m_originalBlocs["red"] = new Bloc("red", *m_sprites.Find("red"));*/
}

BlocManager::~BlocManager()
{
	{
		std::map<std::string, std::vector<Bloc*> >::iterator it = m_blocs.begin();
		for (; it != m_blocs.end(); ++it)
		{
			int max = it->second.size();
			for (int i = 0; i < max; i++)
			{
				if (it->second[i] != NULL)
				{
					delete it->second[i];
					it->second[i] = NULL;
				}
			}
		}
	}
	m_blocs.clear();

	{
		std::map<std::string, Bloc*>::iterator it = m_originalBlocs.begin();
		for (; it != m_originalBlocs.end(); ++it)
			if (it->second != NULL)
				delete it->second;
	}
	m_originalBlocs.clear();
}

void BlocManager::Add(std::string const& _type, Rect const& _position)
{
	Bloc const* b = this->Find(_type);
	if (b == NULL)
		return ;

	Bloc* copy = new Bloc("", Sprite());
	b->Duplicate(*copy);
	copy->SetPosition(_position);
	m_blocs[_type].push_back(copy);
}

void BlocManager::AddOriginal(std::string const& _type)
{
	Sprite const* s = m_sprites.Find(_type);
	if (s != NULL)
		m_originalBlocs[_type] = new Bloc(_type, *s);
}

bool BlocManager::Remove(Bloc* _bloc)
{
	std::map<std::string, std::vector<Bloc*> >::iterator it = m_blocs.begin();
	for (; it != m_blocs.end(); ++it)
	{
		std::vector<Bloc*>::iterator itb =
			std::find(it->second.begin(), it->second.end(), _bloc);
		if (itb != it->second.end())
		{
			Bloc* tmp = *itb;
			it->second.erase(itb);
			delete tmp;
			return (true) ;
		}
	}
	return (false);
}

bool BlocManager::Remove(std::string const& _type, Bloc* _bloc)
{
	Bloc const* b = this->Find(_type);
	if (b == NULL)
		return (false);

	std::vector<Bloc*>::iterator itb =
		std::find(m_blocs[_type].begin(), m_blocs[_type].end(), _bloc);
	if (itb != m_blocs[_type].end())
	{
		Bloc* tmp = *itb;
		m_blocs[_type].erase(itb);
		delete tmp;
		return (true) ;
	}
	return (false);
}

void BlocManager::Clear()
{
	std::map<std::string, std::vector<Bloc*> >::iterator it = m_blocs.begin();
	for (; it != m_blocs.end(); ++it)
	{
		int max = it->second.size();
		for (int i = 0; i < max; i++)
		{
			if (it->second[i] != NULL)
				delete it->second[i];
		}
		it->second.clear();
	}
	m_blocs.clear();
}

void BlocManager::ClearOriginals()
{
	std::map<std::string, Bloc*>::iterator it = m_originalBlocs.begin();
	for (; it != m_originalBlocs.end(); ++it)
	{
		if (it->second != NULL)
			delete it->second;
	}
	m_originalBlocs.clear();
}

void BlocManager::Draw(SDL_Surface* _screen)
{
	std::map<std::string, std::vector<Bloc*> >::iterator it = m_blocs.begin();
	for (; it != m_blocs.end(); ++it)
	{
		int max = it->second.size();
		for (int i = 0; i < max; i++)
			it->second[i]->Draw(_screen);
	}
}

Bloc* BlocManager::Find(std::string const& _type)
{
	std::map<std::string, Bloc*>::iterator it = m_originalBlocs.find(_type);
	if (it != m_originalBlocs.end())
		return (it->second);
	return (NULL);
}

Bloc* BlocManager::GetAt(Sint16 _x, Sint16 _y)
{
	std::map<std::string, std::vector<Bloc*> >::iterator it = m_blocs.begin();
	for (; it != m_blocs.end(); ++it)
	{
		int max = it->second.size();
		for (int i = 0; i < max; i++)
			if (it->second[i]->GetPosition().GetX() == _x && it->second[i]->GetPosition().GetY() == _y)
				return (it->second[i]);
	}
	return (NULL);
}

std::map<std::string, Bloc*>& BlocManager::GetOriginals()
{
	return (m_originalBlocs);
}

void BlocManager::GetOriginals(std::vector<Bloc*>& _dst)
{
	std::map<std::string, Bloc*>::const_iterator it = m_originalBlocs.begin();
	for (; it != m_originalBlocs.end(); ++it)
		_dst.push_back(it->second);
}

std::map<std::string, std::vector<Bloc*> >& BlocManager::GetBlocs()
{
	return (m_blocs);
}

void BlocManager::GetBlocs(std::string const& _type, std::vector<Bloc*>& _dst)
{
	if (m_blocs.find(_type) == m_blocs.end())
		return ;
	_dst = m_blocs[_type];
}

void BlocManager::GetAllBlocs(std::vector<Bloc*>& _dst)
{
	std::map<std::string, std::vector<Bloc*> >::iterator it = m_blocs.begin();
	for (; it != m_blocs.end(); ++it)
	{
		int max = it->second.size();
		for (int i = 0; i < max; i++)
			_dst.push_back(it->second[i]);
	}
}

Sprites& BlocManager::GetSprites()
{
	return (m_sprites);
}
